import { EntityManager, MikroORM } from "@mikro-orm/mysql"

//import 'knex';
import { Knex, knex } from 'knex';

// declare module 'knex' {
//   namespace Knex {
    interface Knext extends Knex<any, any[]> {
            fromORM(entityName,as?:string) : Knex.QueryBuilder
            tableName(entityName,as?:string) : string,
            tableRaw(entityName,as?:string) : Knex.Raw
            tableField(entityName,fieldName:string) : string
            fieldsAll<T>(entityName) : string[]
            fieldsNoId<T>(entityName) : string[]
            fieldsExcludes<T>(entityName,excludes: (keyof T)[]) : string[]
            fieldsIncludes<T>(entityName,includes: (keyof T)[]) : string[]
        }
//    }
// }

export function knext(controller,orm=null,em=null)  {
    const _orm = (orm || controller.orm) as MikroORM 
    //const _em = (em || controller.em) as EntityManager
    let _knext : Knext = knex({
        client:'mysql',
        connection:{
            database: 'zp_apesk_net',
            user: 'zp_apesk_net',
            password: '88888888',
            host: '192.168.1.6',
            port: 3306,
        }
    }) as Knext // _em.getKnex() as any

    _knext.tableName = function (entityName,as?:string){
        const meta = _orm.getMetadata(entityName)
        return as?meta.collection+' AS ' + as : meta.collection
    }
    
    _knext.tableField = function (entityName,fieldName:string){
      const meta = _orm.getMetadata(entityName)
      return meta.collection + '.' + fieldName
    }
    
    _knext.tableRaw = function (entityName,as?:string){
      return _knext.raw(this.tableName(entityName,as))
    }
    
    _knext.fromORM = function(entityName,as?:string) {
       let qq = _knext.queryBuilder()
       const qb = _knext.queryBuilder().fromORM(entityName,_orm,as)
        qb['_knex'] = _knext
        return qb
    }

    _knext.fieldsExcludes = function(entityName,excludes) {
        const meta = _orm.getMetadata(entityName)

        let props = meta.comparableProps

        if(excludes)
        {
            props = props.filter(prop=>!excludes.some(key=>key == prop.name))
        }

        props = props.filter(prop=>prop.reference == 'scalar' && prop.name != 'removeAt')
        
        let keys = props.map(prop=>{
            let name = prop.name as string
            let parts = name.match(/([0-9|a-z]+)|([A-Z][0-9|a-z]+)+?/g);
            return parts.map(part=>part.toLowerCase()).join('_')
        })
 
        return keys
    }

    _knext.fieldsIncludes = function(entityName,includes) {
        const meta = _orm.getMetadata(entityName)

        let props = meta.comparableProps
        //let _includes = [...includes,'removedAt']
        props = props.filter(prop=>includes.some(key=>key == prop.name) && prop.reference == 'scalar' && prop.name != 'removeAt')
        
        let keys = props.map(prop=>{
            let name = prop.name as string
            let parts = name.match(/([0-9|a-z]+)|([A-Z][0-9|a-z]+)+?/g);
            return parts.map(part=>part.toLowerCase()).join('_')
        })
 
        return keys
    }

    _knext.fieldsAll = function(entityName) {
        const meta = _orm.getMetadata(entityName)

        let props = meta.comparableProps
        props = props.filter(prop=>prop.reference == 'scalar' && prop.name != 'removedAt')
        
        let keys = props.map(prop=>{
            let name = prop.name as string
            let parts = name.match(/([0-9|a-z]+)|([A-Z][0-9|a-z]+)+?/g);
            return parts.map(part=>part.toLowerCase()).join('_')
        })
 
        return keys
    }

    // fieldsNoId(entityName) {

    // }

    // fieldsExclude<T>(entityName,exclude: (keyof T)[]) : string[]
    // fieldsInclude<T>(entityName,exclude: (keyof T)[]) : string[]
 
    return  _knext as Knext
}



// export function knext(controller) {
//     return new _knext(controller)
// }